﻿using System;
using System.Threading;

namespace Chengqbd.Core.Common
{
	public class IdWorker
	{
		public static long WorkerId
		{
			get
			{
				return IdWorker._workerId;
			}
			set
			{
				bool flag = value > 0L && value < IdWorker.maxWorkerId;
				if (flag)
				{
					IdWorker._workerId = value;
					return;
				}
				throw new Exception("Workerid must be greater than 0 or less than " + IdWorker.maxWorkerId);
			}
		}

		static IdWorker()
		{
			IdWorker._workerId = (long)new Random(DateTime.UtcNow.Millisecond).Next(1, (int)IdWorker.maxWorkerId);
		}
        /// <summary>
        /// 生成新的id
        /// </summary>
        /// <returns></returns>
		public static long NewId()
		{
			bool flag = false;
			long result;
			try
			{
				IdWorker._lock.Enter(ref flag);
				long num = IdWorker.GetTimeStamp();
				bool flag2 = IdWorker.lastTimestamp == num;
				if (flag2)
				{
					IdWorker.sequence = (IdWorker.sequence + 1L & IdWorker.sequenceMask);
					bool flag3 = IdWorker.sequence == 0L;
					if (flag3)
					{
						num = IdWorker.TillNextMillis(IdWorker.lastTimestamp);
					}
				}
				else
				{
					IdWorker.sequence = 0L;
				}
				bool flag4 = num < IdWorker.lastTimestamp;
				if (flag4)
				{
					throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds", IdWorker.lastTimestamp - num));
				}
				IdWorker.lastTimestamp = num;
				result = (num - IdWorker._twepoch << IdWorker.timestampLeftShift | IdWorker._workerId << IdWorker.workerIdShift | IdWorker.sequence);
			}
			finally
			{
				bool flag5 = flag;
				if (flag5)
				{
					IdWorker._lock.Exit();
				}
			}
			return result;
		}

		private static long TillNextMillis(long lastTimestamp)
		{
			long timeStamp;
			for (timeStamp = IdWorker.GetTimeStamp(); timeStamp <= lastTimestamp; timeStamp = IdWorker.GetTimeStamp())
			{
			}
			return timeStamp;
		}

		private static long GetTimeStamp()
		{
			return (DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks) / 10000L;
		}

		private static long _workerId;

		private static readonly long _twepoch = 1557878400000L;

		private static long sequence = 0L;

		private static readonly int workerIdBits = 4;

		private static readonly long maxWorkerId = -1L ^ -1L << IdWorker.workerIdBits;

		private static readonly int sequenceBits = 12;

		private static readonly int workerIdShift = IdWorker.sequenceBits;

		private static readonly int timestampLeftShift = IdWorker.sequenceBits + IdWorker.workerIdBits;

		private static readonly long sequenceMask = -1L ^ -1L << IdWorker.sequenceBits;

		private static long lastTimestamp = -1L;

		private static SpinLock _lock = default(SpinLock);
	}
}
